/*
 * sgc_chat_connections.c
 *
 *  Created on: 2011-7-11
 *      Author: rendong
 */
#include "sgc_chat_connections.h"
#include "sgc_chat_logic_flash.h"
#include <unistd.h>

sgc_inthash_table_t * sgc_all_sessions; //  fd => session
sgc_hash_table_t * sgc_all_userids; // userid => session
sgc_hash_table_t * sgc_all_channels; // channelname => list<session>

/**
 * 新用户连接
 */
void chat_client_new_handler(int fd, struct sockaddr_in *clientaddr,  sgc_epoll_socketserver_config_t const* config)
{
	sgc_chat_session_t * session = (sgc_chat_session_t*) malloc(sizeof(sgc_chat_session_t));
	memset(session, 0, sizeof(sgc_chat_session_t));
	session->fd = fd;
	session->buffer = (char *)malloc(cfg_user_buffersize);
	session->buffersize = cfg_user_buffersize;
	session->bufferpos = 0;
	session->channels = sgc_list_create();
	session->friends = sgc_list_create();
	session->count = 0;

	struct sockaddr_in *client = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
	memcpy(client, clientaddr, sizeof(struct sockaddr_in));
	session->clientaddr = client;

	session->config = config;

	if (sgc_inthash_put(sgc_all_sessions, fd, session))
	{
		sgc_log_error("fd exists:%d, %s\n", fd, inet_ntoa(clientaddr->sin_addr));
	}

	sgc_log_debug("chat_client_new_handler, fd:%d %p\n", fd, session);
}

/**
 * 消息处理
 */
void chat_client_message_handler(int fd, char const * buffer, int length)
{
	sgc_chat_session_t * session = sgc_inthash_get(sgc_all_sessions, fd);
	if (session == NULL){
		sgc_log_error("session not found,fd=%d\n", fd);
		return;
	}

	int remain = session->buffersize - session->bufferpos;

	// 扩充buffer
	if (remain < length){
		char * newbuffer = (char *)malloc(session->bufferpos + length);
		memset(newbuffer, 0, session->bufferpos + length);

		memcpy(newbuffer, session->buffer, session->bufferpos);
		free(session->buffer);
		session->buffer = newbuffer;
		session->buffersize = session->bufferpos + length;
	}

	memcpy(session->buffer+session->bufferpos, buffer, length);
	session->bufferpos += length;

	int len = *(int *)session->buffer;

	// 如果包长足够，则处理消息
	while (len > 0 && session->bufferpos > 0 && session->bufferpos>=(len+PKG_LEN_SIZE)){
		session->count++;
		short type = *(short *)(session->buffer + PKG_LEN_SIZE);

		// 处理消息
		char * message = malloc(len - PKG_TYPE_SIZE);
		memcpy(message, session->buffer+PKG_HEAD_SIZE, len - PKG_TYPE_SIZE);

		// 复制剩下的buffer到session buffer头部
		remain = session->bufferpos - len - PKG_LEN_SIZE;
		if (remain < cfg_user_buffersize)
			remain = cfg_user_buffersize;

		char * remainbuffer = malloc(remain);
		memset(remainbuffer, 0, remain);
		memcpy(remainbuffer, session->buffer+len+PKG_LEN_SIZE, session->bufferpos - len - PKG_LEN_SIZE);

		free(session->buffer);
		session->buffer = remainbuffer;
		session->buffersize = remain;
		session->bufferpos = session->bufferpos - len - PKG_LEN_SIZE;

		sgc_log_debug("chat_message_dispatch fd:%d msgcount:%d len:%d, type;%d\n",session->fd, session->count, len-PKG_TYPE_SIZE, type);
		chat_message_dispatch(session, len-PKG_TYPE_SIZE, type, message);
		free(message);

		len = *(int *) session->buffer;
	}
}

/**
 * 关闭
 */
void chat_client_close_hander(int fd)
{
	sgc_chat_session_t * session = sgc_inthash_get(sgc_all_sessions, fd);
	sgc_chat_session_t * fsession, *tsession;

	// 释放和session相关的内存
	if (session != NULL){
		sgc_inthash_del(sgc_all_sessions, fd);

		session->config = NULL;
		free(session->clientaddr);
		free(session->buffer);

		// 释放和频道相关的资源
		char * channelname = NULL;
		channelname = sgc_list_pop(session->channels);
		while(channelname != NULL){
			sgc_list_t * channel_list = sgc_hash_get(sgc_all_channels, channelname);
			if (channel_list != NULL){
				sgc_log_debug("del from all_channels, name:%s %p\n", channelname, session);
				sgc_list_del(channel_list, session);
			}
			free(channelname);
			channelname = sgc_list_pop(session->channels);
		}
		free(session->channels);

		// 释放好友列表
		if (session->userid != NULL)
		{
			sgc_chat_message_t data_down;
			data_down.len = PKG_HEAD_SIZE + PKG_LEN_SIZE + strlen (session->userid);
			data_down.message = malloc(data_down.len);
			short data_down_type = 503;
			int userid_len = strlen(session->userid);
			int pkg_len = data_down.len - PKG_LEN_SIZE;
			memcpy(data_down.message, &pkg_len, PKG_LEN_SIZE);
			memcpy(data_down.message+PKG_LEN_SIZE, &data_down_type, PKG_TYPE_SIZE);
			memcpy(data_down.message+PKG_HEAD_SIZE, &userid_len, PKG_LEN_SIZE);
			memcpy(data_down.message+PKG_HEAD_SIZE+PKG_LEN_SIZE, session->userid, userid_len);

			char * fid = NULL;
			fid = sgc_list_pop(session->friends);
			while(fid != NULL){
				fsession = sgc_hash_get(sgc_all_userids, fid);

				if (fsession != NULL && fsession->login_type == LOGIN_TYPE_USER){// 发送下线通知
					if (writen(fsession->fd, data_down.message, data_down.len) == -1)
					{
						// ignore
					}
				}
				free(fid);
				fid = sgc_list_pop(session->friends);
			}
			free(session->friends);
			free(data_down.message);
		}else{
			free(session->friends);
		}

		// 释放个人信息
		if (session->userid != NULL){
			// 所有用户列表里面删除，有效才删除，重复登录情况下，最后一个有效
			tsession = sgc_hash_get(sgc_all_userids, session->userid);
			if (tsession == session){
				sgc_log_debug("del from sgc_all_userids, userid:%s\n", session->userid);
				sgc_hash_del(sgc_all_userids, session->userid);
			}
			free(session->userid);
		}

		if (session->username != NULL)
			free(session->username);

		free(session);
	}

	sgc_log_debug("epoll_client_close_hander_t fd:%d\n\n", fd);
}

/**
 * 启动服务
 */
void sgc_start_chat_server()
{
	// 初始化会话数据
	sgc_all_sessions = (sgc_inthash_table_t *)malloc(sizeof(sgc_inthash_table_t));
	sgc_inthash_init(sgc_all_sessions, cfg_maxclients);

	// 初始化频道数据
	sgc_all_channels = (sgc_hash_table_t *) malloc(sizeof(sgc_hash_table_t));
	int capacity = cfg_maxclients / 100;
	if (capacity < 100)
		capacity = 100;

	sgc_hash_init(sgc_all_channels, capacity);

	sgc_all_userids = malloc(sizeof(sgc_hash_table_t));
	sgc_hash_init(sgc_all_userids, cfg_maxclients);

	// 初始化配置
	sgc_epoll_socketserver_config_t config;
	config.buffer_size = cfg_buffersize;
	config.local_addr = cfg_local_addr;
	config.port = cfg_port;
	config.cfgmaxclients = cfg_maxclients;

	config.handler_new = chat_client_new_handler;
	config.hander_read = chat_client_message_handler;
	config.hander_close = chat_client_close_hander;

	sgc_serversocket_start(&config);
}

/**
 * 协议处理
 */
void chat_message_dispatch(sgc_chat_session_t * session, int len,int type, char * message)
{
	//  判断登录
	if (session->login_type == LOGIN_TYPE_NOLOGIN && type != 100)
		return;

	switch (type){
	case 100:
		chat_message_flash_auth(session, len, type, message);
		break;
	case 103:
	case 104:
	case 105:
		chat_message_flash_chat(session, len, type, message);
		break;
	case 102:
		chat_message_flash_addchannel(session, len, type, message);
		break;
	case 101:
		chat_message_flash_friend(session, len, type, message);
		break;
	case 500:// 查看服务器状态
		chat_message_admin_status(session, len, type, message);
		break;
	default:
		sgc_log_error("Message type not found, fd=%d type=%d\n", session->fd, type);
	}
}
